package com.zengdada.dml.utils;

import com.zengdada.authority.utils.CommonUtils;
import com.zengdada.dml.model.DmlColumnExtend;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 解析sql语句
 * 普通sql
 * ?
 * {request.getParamt..("id")} ?
 * {getUserId()}  ?
 * {int:getName()?10!名称} int 类型，表达式是 getName()，默认值 10，必填，标题 名称
 *
 * @author zengshunan
 */
public class TaggedSql {


    protected static final Pattern TAG_PATTERN = Pattern.compile("(?<escaper>[\\\\])?\\{(?<type>(decimal|int|long|double|float|string|datetime):)?(?<expr>[^?!\\}]+)(?<def>[?][^\\}!]+)?(?<req>[!])?(?<caption>[^\\}]+)?\\}");

    private String text;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    private final List<Tag> tags = new ArrayList<>();

    public List<Tag> getTags() {
        return tags;
    }

    public static class Tag {

        private String expr;
        private Class<?> dataType;
        private boolean required;
        private Object defaultValue;

        public String getExpr() {
            return expr;
        }

        public void setExpr(String expr) {
            this.expr = expr;
        }

        public Class<?> getDataType() {
            return dataType;
        }

        public void setDataType(Class<?> dataType) {
            this.dataType = dataType;
        }

        public boolean isRequired() {
            return required;
        }

        public void setRequired(boolean required) {
            this.required = required;
        }

        public Object getDefaultValue() {
            return defaultValue;
        }

        public void setDefaultValue(Object defaultValue) {
            this.defaultValue = defaultValue;
        }

    }

    protected final static HashMap<String, Class<?>> TYPE_MAP = new HashMap<>();

    static {
        TYPE_MAP.put("string", String.class);
        TYPE_MAP.put("int", Integer.class);
        TYPE_MAP.put("long", Long.class);
        TYPE_MAP.put("float", Float.class);
        TYPE_MAP.put("double", Double.class);
        TYPE_MAP.put("datetime", java.util.Date.class);
        TYPE_MAP.put("decimal", BigDecimal.class);
    }

    public static TaggedSql compile(String text, List<DmlColumnExtend> columns) throws ParseException {

        TaggedSql taggedText = new TaggedSql();

        StringBuffer buf = new StringBuffer();
        Matcher m = TAG_PATTERN.matcher(text);
        while (m.find()) {
            Tag tag = new Tag();
            String escaper = m.group("escaper"),
                    type = m.group("type"),
                    expr = m.group("expr"),
                    def = m.group("def"),
                    required = m.group("req"),
                    caption = m.group("caption");

            if (escaper != null) {
                m.appendReplacement(buf, m.group().substring(1));
                continue;
            }
            tag.setDataType(TYPE_MAP.get(type == null ? "string" : type.substring(0, type.length() - 1)));
            tag.setExpr(expr);
            tag.setDefaultValue(def == null ? null : org.apache.commons.beanutils.ConvertUtils.convert(def.substring(1), tag.getDataType()));
            tag.setRequired((required != null));
            m.appendReplacement(buf, "?");
            //  计算当前位置前面的 ？ 数
            String temp = buf.toString();
            //  寻找位置
            int count = CommonUtils.zInStrAppearCount(temp, "\\?");
            taggedText.getTags().add(tag);
            DmlColumnExtend column = new DmlColumnExtend(String.format("plat_expr%d", count), tag.getExpr(), tag.getDataType());
            column.setColumnType(DmlColumnExtend.IN_PARAM_COLUMN);
            column.setDefaultValue(tag.getDefaultValue());
            column.setCaption(caption);
            if (tag.isRequired()) {
                column.setAttr(DmlColumnExtend.ATTR_REQUIRED, true);
            }
            // 指定位置插入字段
            columns.add(count - 1, column);
        }
        m.appendTail(buf);
        taggedText.setText(buf.toString());
        return taggedText;
    }

    public static void main(String[] args) {
        try {
            TaggedSql compile = TaggedSql.compile("select * from dual where {int:getName()?10!这是name?a:!}", new ArrayList<>());
            System.out.println();
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}
